use std::{sync::Arc, time::Duration};

use clap::Parser;
use reqwest::Client;
use tokio::sync::RwLock;

use crate::{
    config::Config,
    monitor::{
        collect_system_stats, dns_lookup, http_bench, parse_ports, ping, portscan, tcping,
        ws_bench, DnsOptions, HttpBenchOptions, NicMonitor, PingOptions, PortscanOptions,
        TcpingOptions, WsBenchOptions,
    },
};

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub enum Cli {
    /// 启动/控制服务
    #[command(name = "start")]
    Start,
    /// 内部使用：实际运行服务进程
    #[command(name = "__run_server", hide = true)]
    RunServer,
    /// 服务状态
    #[command(name = "status")]
    Status,
    /// 服务热加载配置
    #[command(name = "reload")]
    Reload,
    /// 停止服务
    #[command(name = "stop")]
    Stop,
    /// 获取系统监控数据（CPU/内存/硬盘）
    System,
    /// 获取网络监控数据（多网卡流量）
    Network,
    /// 执行 ICMP Ping 探测
    Ping {
        /// 目标主机（IP 或域名）
        target: String,
        /// 探测次数
        #[arg(short, long, default_value_t = 4)]
        count: u32,
        /// 单次超时时间（毫秒）
        #[arg(long, default_value_t = 1000)]
        timeout_ms: u64,
    },
    /// 执行 TCP 连接探测
    Tcping {
        /// 目标主机（IP 或域名）
        target: String,
        /// 目标端口
        #[arg(short, long)]
        port: u16,
        /// 探测次数
        #[arg(short, long, default_value_t = 4)]
        count: u32,
        /// 单次超时时间（毫秒）
        #[arg(long, default_value_t = 1000)]
        timeout_ms: u64,
    },
    /// 执行 DNS 查询
    Dns {
        /// 查询的域名
        domain: String,
        /// 记录类型（A、AAAA、MX、TXT 等）
        #[arg(short, long, default_value = "A")]
        record_type: String,
    },
    /// 执行端口扫描
    Portscan {
        /// 目标主机（IP 或域名）
        target: String,
        /// 端口列表，支持逗号分隔与范围（如 22,80,443,1000-1010）
        ports: String,
        /// 单端口超时时间（毫秒）
        #[arg(long, default_value_t = 500)]
        timeout_ms: u64,
        /// 并发数
        #[arg(long, default_value_t = 50)]
        concurrency: usize,
    },
    /// HTTP/HTTPS 压力测试（类似 ab）
    HttpBench {
        /// 目标 URL
        url: String,
        /// 请求总数
        #[arg(short = 'n', long, default_value_t = 100)]
        requests: u32,
        /// 并发数
        #[arg(short = 'c', long, default_value_t = 10)]
        concurrency: usize,
        /// 超时时间（毫秒）
        #[arg(long, default_value_t = 1000)]
        timeout_ms: u64,
    },
    /// WebSocket 并发测试
    WsBench {
        /// 目标 WS/WSS 地址
        url: String,
        /// 建立连接总数
        #[arg(short = 'n', long, default_value_t = 50)]
        connections: u32,
        /// 最多同时进行的连接数
        #[arg(short = 'c', long, default_value_t = 10)]
        concurrency: usize,
        /// 每个连接发送的消息数量
        #[arg(long, default_value_t = 0)]
        messages: u32,
        /// 文本消息内容（为空则发送 ping）
        #[arg(long)]
        payload: Option<String>,
        /// 超时时间（毫秒）
        #[arg(long, default_value_t = 1000)]
        timeout_ms: u64,
    },
}

#[derive(Debug, Clone, Copy)]
pub enum ServerAction {
    Status,
    Reload,
    Stop,
}

pub async fn run_cli(command: Cli, monitor: &NicMonitor) {
    match command {
        Cli::Start => unreachable!("server start handled in main"),
        Cli::RunServer => unreachable!("internal server runner handled in main"),
        Cli::Status => unreachable!("server status handled in main"),
        Cli::Reload => unreachable!("server reload handled in main"),
        Cli::Stop => unreachable!("server stop handled in main"),
        Cli::System => {
            let stats = collect_system_stats();
            println!("{}", serde_json::to_string_pretty(&stats).unwrap());
        }
        Cli::Network => {
            let stats = monitor.collect_stats();
            println!("{}", serde_json::to_string_pretty(&stats).unwrap());
        }
        Cli::Ping {
            target,
            count,
            timeout_ms,
        } => {
            let result = ping(PingOptions {
                target: &target,
                count,
                timeout: Duration::from_millis(timeout_ms),
            })
            .await;
            println!("{}", serde_json::to_string_pretty(&result).unwrap());
        }
        Cli::Tcping {
            target,
            port,
            count,
            timeout_ms,
        } => {
            let result = tcping(TcpingOptions {
                target: &target,
                port,
                count,
                timeout: Duration::from_millis(timeout_ms),
            })
            .await;
            println!("{}", serde_json::to_string_pretty(&result).unwrap());
        }
        Cli::Dns {
            domain,
            record_type,
        } => {
            let result = dns_lookup(DnsOptions {
                query: &domain,
                record_type: &record_type,
            })
            .await;
            println!("{}", serde_json::to_string_pretty(&result).unwrap());
        }
        Cli::Portscan {
            target,
            ports,
            timeout_ms,
            concurrency,
        } => match parse_ports(&ports) {
            Ok(ports) => {
                let result = portscan(PortscanOptions {
                    target: &target,
                    ports,
                    timeout: Duration::from_millis(timeout_ms),
                    concurrency,
                })
                .await;
                println!("{}", serde_json::to_string_pretty(&result).unwrap());
            }
            Err(err) => {
                eprintln!("{err}");
            }
        },
        Cli::HttpBench {
            url,
            requests,
            concurrency,
            timeout_ms,
        } => {
            let result = http_bench(HttpBenchOptions {
                url: &url,
                requests,
                concurrency,
                timeout_ms,
            })
            .await;
            println!("{}", serde_json::to_string_pretty(&result).unwrap());
        }
        Cli::WsBench {
            url,
            connections,
            concurrency,
            messages,
            payload,
            timeout_ms,
        } => {
            let result = ws_bench(WsBenchOptions {
                url: &url,
                connections,
                concurrency,
                messages,
                payload: payload.as_deref(),
                timeout_ms,
            })
            .await;
            println!("{}", serde_json::to_string_pretty(&result).unwrap());
        }
    }
}

pub async fn handle_server_action(
    action: ServerAction,
    config: Arc<RwLock<Config>>,
) -> Result<(reqwest::StatusCode, serde_json::Value), String> {
    let snapshot = config.read().await.clone();
    let base = format!("http://127.0.0.1:{}/api/admin", snapshot.server.http_port);
    let token = snapshot.security.token.clone();

    let client = Client::builder()
        .timeout(Duration::from_secs(30))
        .build()
        .map_err(|err| err.to_string())?;

    let add_token = |builder: reqwest::RequestBuilder| {
        if token.is_empty() {
            builder
        } else {
            builder.query(&[("token", token.as_str())])
        }
    };

    let request_builder = match action {
        ServerAction::Stop => add_token(client.post(format!("{}/stop", base))),
        ServerAction::Reload => add_token(client.post(format!("{}/reload", base))),
        ServerAction::Status => add_token(client.get(format!("{}/status", base))),
    };

    let response = request_builder
        .send()
        .await
        .map_err(|err| err.to_string())?;

    let status = response.status();
    let body: serde_json::Value = response.json().await.map_err(|err| err.to_string())?;

    Ok((status, body))
}
